﻿using System;
using System.Collections.Generic;
using Jay.Sc2.Bof.Lib.Action;
using Jay.Sc2.Bof.Lib.Action.Protoss;

namespace Jay.Sc2.Bof.Lib.State
{
	public class ProtossState : State
	{
		public ProtossState() : base(ProtossRace.Instance) { }
		public class ProtossBuilding : StateBuilding
		{
			public ProtossBuilding Clone()
			{
				ProtossBuilding clone = new ProtossBuilding();
				clone.Building = Building;
				clone.Count = Count;
				return clone;
			}
		}
		public class ProtossProductionBuilding : ProtossBuilding
		{
			public virtual int AvailableForProduction { get { return Count - Production; } }
			public int AvailableForUpgrade { get { return Count - Upgrade; } }
			public override int Available { get { return Math.Min(AvailableForProduction, AvailableForUpgrade); } }
			public void Produced() { Production--; }
			public void Upgraded() { Upgrade--; }
			public int Production;
			public int Upgrade;
			public int ChronoBoosted;
			public int ProductionWithChronoBoost;
			public int AvailableWithChonoBoost { get { return ChronoBoosted - ProductionWithChronoBoost; } }
			public int NotChronoBoosted { get { return Count - ChronoBoosted; } }
			public new ProtossProductionBuilding Clone()
			{
				ProtossProductionBuilding clone = new ProtossProductionBuilding();
				clone.Building = Building;
				clone.Count = Count;
				clone.Production = Production;
				clone.Upgrade = Upgrade;
				clone.ChronoBoosted = ChronoBoosted;
				clone.ProductionWithChronoBoost = ProductionWithChronoBoost;
				return clone;
			}
		}
		public class ProtossUpgrade : StateUpgrade
		{
			public ProtossUpgrade Clone()
			{
				ProtossUpgrade clone = new ProtossUpgrade();
				clone.Available = Available;
				clone.Researching = Researching;
				return clone;
			}
		}

		public static ProtossState CreateInitialState()
		{
			ProtossState state = new ProtossState();
			state.Nexus.Count = 1;
			// maybe nexus starts with more energy ? dunno :s have to see in game ...
			state.Nexus_Energy.Add(0.0);
			state.Minerals = 50;
			state.WorkersOnMinerals = state.Food = state.Probe = 6;
			state.Supply = state.Nexus.Count * 10;
			return state;
		}

		public ProtossProductionBuilding Nexus = new ProtossProductionBuilding();
		public ProtossBuilding Pylon = new ProtossBuilding();
		public ProtossBuilding Assimilator = new ProtossBuilding();
		public ProtossProductionBuilding Gateway = new ProtossProductionBuilding();
		public ProtossBuilding Forge = new ProtossProductionBuilding();
		public ProtossBuilding PhotonCannon = new ProtossBuilding();
		public ProtossProductionBuilding WarpGate = new ProtossProductionBuilding();
		public ProtossProductionBuilding CyberneticsCore = new ProtossProductionBuilding();
		public ProtossProductionBuilding TwilightCouncil = new ProtossProductionBuilding();
		public ProtossProductionBuilding RoboticsFacility = new ProtossProductionBuilding();
		public ProtossProductionBuilding Stargate = new ProtossProductionBuilding();
		public ProtossProductionBuilding TemplarArchives = new ProtossProductionBuilding();
		public ProtossProductionBuilding DarkShrine = new ProtossProductionBuilding();
		public ProtossProductionBuilding RoboticsBay = new ProtossProductionBuilding();
		public ProtossProductionBuilding FleetBeacon = new ProtossProductionBuilding();
		public int Probe;
		public int Zealot;
		public int Stalker;
		public int Sentry;
		public int Observer;
		public int Immortal;
		public int WarpPrism;
		public int Colossus;
		public int Phoenix;
		public int VoidRay;
		public int HighTemplar;
		public int HighTemplarProducing;
		public int DarkTemplar;
		public int DarkTemplarProducing;
		public int Archon;
		public int Carrier;
		public int Interceptor;
		public int Mothership;
		public ProtossUpgrade GatewayToWarpGate = new ProtossUpgrade();

		public List<double> Nexus_Energy = new List<double>();
		public override void IncrementTime()
		{
			base.IncrementTime();
			for (int c = 0; c < Nexus_Energy.Count; c++)
				if (Nexus_Energy[c] < 200)
					Nexus_Energy[c] = Math.Min(Nexus_Energy[c] + 0.56, 200);
		}

		public override IBuilding Bases { get { return Nexus; } }
		public override IBuilding GasBuilding { get { return Assimilator; } }

		public override int Army
		{
			get
			{
				return Zealot * 2 +
					Stalker * 2 +
					Sentry * 2 +
					Observer +
					Immortal * 4 +
					WarpPrism * 2 +
					Colossus * 6 +
					Phoenix * 2 +
					VoidRay * 3 +
					HighTemplar * 2 +
					DarkTemplar * 2 +
					Archon * 4 +
					Carrier * 6 +
					Mothership * 8;
			}
		}

		public override int Workers { get { return Probe; } set { Probe = value; } }

		public override double Score(IState state)
		{
			ProtossState s = state as ProtossState;
			double score = 0.0;
			score += Score(Probe, s.Probe, 50.0);
			score += Score(Zealot, s.Zealot, 100.0);
			score += Score(Stalker, s.Stalker, 175.0);
			score += Score(Sentry, s.Sentry, 150.0);
			score += Score(Observer, s.Observer, 150.0);
			score += Score(Immortal, s.Immortal, 350.0);
			score += Score(WarpPrism, s.WarpPrism, 200.0);
			score += Score(Colossus, s.Colossus, 500.0);
			score += Score(Phoenix, s.Phoenix, 250.0);
			score += Score(VoidRay, s.VoidRay, 400.0);
			score += Score(HighTemplar, s.HighTemplar, 200);
			score += Score(DarkTemplar, s.DarkTemplar, 250.0);
			score += Score(Archon, s.Archon, 400.0);
			score += Score(Carrier, s.Carrier, 600.0);
			score += Score(Interceptor, s.Interceptor, 25.0);
			score += Score(Mothership, s.Mothership, 800.0);
			score += Score(Nexus, s.Nexus, 400.0);
			score += Score(Pylon, s.Pylon, 100.0);
			score += Score(Assimilator, s.Assimilator, 75.0);
			score += Score(Gateway, s.Gateway, 150.0);
			score += Score(Forge, s.Forge, 150.0);
			score += Score(PhotonCannon, s.PhotonCannon, 150.0);
			score += Score(WarpGate, s.WarpGate, 150.0);
			score += Score(CyberneticsCore, s.CyberneticsCore, 150.0);
			score += Score(TwilightCouncil, s.TwilightCouncil, 250.0);
			score += Score(RoboticsFacility, s.RoboticsFacility, 300.0);
			score += Score(Stargate, s.Stargate, 300.0);
			score += Score(TemplarArchives, s.TemplarArchives, 450.0);
			score += Score(DarkShrine, s.DarkShrine, 350.0);
			score += Score(RoboticsBay, s.RoboticsBay, 400.0);
			score += Score(FleetBeacon, s.FleetBeacon, 500.0);
			///TODO add the upgrades
			score += Score((int)this.Minerals, (int)s.Minerals, 1.0);
			score += Score((int)this.Gas, (int)s.Gas, 1.0);
			return score;
		}

		public override bool IsSatisfying(IState goal)
		{
			ProtossState state = goal as ProtossState;
			if (Archon < state.Archon) return false;
			if (Assimilator.Count < state.Assimilator.Count) return false;
			if (Carrier < state.Carrier) return false;
			if (Colossus < state.Colossus) return false;
			if (CyberneticsCore.Count < state.CyberneticsCore.Count) return false;
			if (DarkShrine.Count < state.DarkShrine.Count) return false;
			if (DarkTemplar < state.DarkTemplar) return false;
			if (FleetBeacon.Count < state.FleetBeacon.Count) return false;
			if (Forge.Count < state.Forge.Count) return false;
			if (Gateway.Count < state.Gateway.Count) return false;
			if (HighTemplar < state.HighTemplar) return false;
			if (Immortal < state.Immortal) return false;
			if (Interceptor < state.Interceptor) return false;
			if (m_SupplyBuilding < state.m_SupplyBuilding) return false;
			if (Mothership < state.Mothership) return false;
			if (Nexus.Count < state.Nexus.Count) return false;
			if (Observer < state.Observer) return false;
			if (Phoenix < state.Phoenix) return false;
			if (PhotonCannon.Count < state.PhotonCannon.Count) return false;
			if (Probe < state.Probe) return false;
			if (Pylon.Count < state.Pylon.Count) return false;
			if (RoboticsBay.Count < state.RoboticsBay.Count) return false;
			if (RoboticsFacility.Count < state.RoboticsFacility.Count) return false;
			if (Sentry < state.Sentry) return false;
			if (Stalker < state.Stalker) return false;
			if (Stargate.Count < state.Stargate.Count) return false;
			if (TemplarArchives.Count < state.TemplarArchives.Count) return false;
			if (TwilightCouncil.Count < state.TwilightCouncil.Count) return false;
			if (VoidRay < state.VoidRay) return false;
			if (WarpGate.Count < state.WarpGate.Count) return false;
			if (WarpPrism < state.WarpPrism) return false;
			if (Zealot < state.Zealot) return false;
			if (Minerals < state.Minerals) return false;
			if (Gas < state.Gas) return false;
			///TODO add the upgrades
			return true;
		}

		public override IState Clone()
		{
			ProtossState clone = new ProtossState();
			clone.Nexus_Energy = new List<double>(Nexus_Energy);
			clone.Food = Food;
			clone.Supply = Supply;
			clone.m_SupplyBuilding = SupplyBuilding;
			clone.Archon = Archon;
			clone.Assimilator = Assimilator.Clone();
			clone.Carrier = Carrier;
			clone.Colossus = Colossus;
			clone.CyberneticsCore = CyberneticsCore.Clone();
			clone.DarkShrine = DarkShrine.Clone();
			clone.DarkTemplar = DarkTemplar;
			clone.FleetBeacon = FleetBeacon.Clone();
			clone.Forge = Forge.Clone();
			clone.Gateway = Gateway.Clone();
			clone.HighTemplar = HighTemplar;
			clone.Immortal = Immortal;
			clone.Interceptor = Interceptor;
			clone.m_SupplyBuilding = m_SupplyBuilding;
			clone.Mothership = Mothership;
			clone.Nexus = Nexus.Clone();
			clone.Observer = Observer;
			clone.Phoenix = Phoenix;
			clone.PhotonCannon = PhotonCannon.Clone();
			clone.Probe = Probe;
			clone.Pylon = Pylon.Clone();
			clone.RoboticsBay = RoboticsBay.Clone();
			clone.RoboticsFacility = RoboticsFacility.Clone();
			clone.Sentry = Sentry;
			clone.Stalker = Stalker;
			clone.Stargate = Stargate.Clone();
			clone.TemplarArchives = TemplarArchives.Clone();
			clone.TwilightCouncil = TwilightCouncil.Clone();
			clone.VoidRay = VoidRay;
			clone.WarpGate = WarpGate.Clone();
			clone.WarpPrism = WarpPrism;
			clone.Zealot = Zealot;
			clone.WorkersOnMinerals = WorkersOnMinerals;
			clone.WorkersOnGas = WorkersOnGas;
			clone.Time = Time;
			clone.Minerals = Minerals;
			clone.Gas = Gas;
			///TODO add the upgrades
			return clone;
		}

		public override IList<IAction> NeededActions
		{
			get
			{
				List<IAction> al = new List<IAction>();
				AddNeededAction(al, Probe - 6, ActionProduceProbe.Instance);
				AddNeededAction(al, Archon, ActionProduceArchon.Instance);
				AddNeededAction(al, Assimilator, ActionProduceAssimilator.Instance);
				AddNeededAction(al, Gateway.Count + WarpGate.Count, ActionProduceGateway.Instance);
				AddNeededAction(al, WarpGate.Count, ActionProduceWarpGate.Instance);
				AddNeededAction(al, Carrier, ActionProduceCarrier.Instance);
				AddNeededAction(al, Colossus, ActionProduceColossus.Instance);
				AddNeededAction(al, CyberneticsCore, ActionProduceCyberneticsCore.Instance);
				AddNeededAction(al, DarkShrine, ActionProduceDarkShrine.Instance);
				AddNeededAction(al, DarkTemplar, ActionProduceDarkTemplar.Instance);
				AddNeededAction(al, FleetBeacon, ActionProduceFleetBeacon.Instance);
				AddNeededAction(al, Forge, ActionProduceForge.Instance);
				AddNeededAction(al, HighTemplar, ActionProduceHighTemplar.Instance);
				AddNeededAction(al, Immortal, ActionProduceImmortal.Instance);
				AddNeededAction(al, Mothership, ActionProduceMothership.Instance);
				AddNeededAction(al, Nexus, ActionProduceNexus.Instance);
				AddNeededAction(al, Observer, ActionProduceObserver.Instance);
				AddNeededAction(al, Phoenix, ActionProducePhoenix.Instance);
				AddNeededAction(al, PhotonCannon, ActionProducePhotonCannon.Instance);
				AddNeededAction(al, Pylon, ActionProducePylon.Instance);
				AddNeededAction(al, RoboticsBay, ActionProduceRoboticsBay.Instance);
				AddNeededAction(al, RoboticsFacility, ActionProduceRoboticsFacility.Instance);
				AddNeededAction(al, Sentry, ActionProduceSentry.Instance);
				AddNeededAction(al, Stalker, ActionProduceStalker.Instance);
				AddNeededAction(al, Stargate, ActionProduceStargate.Instance);
				AddNeededAction(al, TemplarArchives, ActionProduceTemplarArchives.Instance);
				AddNeededAction(al, TwilightCouncil, ActionProduceTwilightCouncil.Instance);
				AddNeededAction(al, VoidRay, ActionProduceVoidRay.Instance);
				AddNeededAction(al, WarpPrism, ActionProduceWarpPrism.Instance);
				AddNeededAction(al, Zealot, ActionProduceZealot.Instance);

				return al;
			}
		}

		public override IActionList BasicBuildOrder
		{
			get
			{
				ActionList al = new ActionList(ProtossRace.Instance);
				AddNeededActionWithRequirements(al, Probe - 6, ActionProduceProbe.Instance);
				AddNeededActionWithRequirements(al, Archon, ActionProduceArchon.Instance);
				AddNeededActionWithRequirements(al, Assimilator, ActionProduceAssimilator.Instance);
				AddNeededActionWithRequirements(al, Gateway.Count + WarpGate.Count, ActionProduceGateway.Instance);
				AddNeededActionWithRequirements(al, WarpGate.Count, ActionProduceWarpGate.Instance);
				AddNeededActionWithRequirements(al, Carrier, ActionProduceCarrier.Instance);
				AddNeededActionWithRequirements(al, Colossus, ActionProduceColossus.Instance);
				AddNeededActionWithRequirements(al, CyberneticsCore, ActionProduceCyberneticsCore.Instance);
				AddNeededActionWithRequirements(al, DarkShrine, ActionProduceDarkShrine.Instance);
				AddNeededActionWithRequirements(al, DarkTemplar, ActionProduceDarkTemplar.Instance);
				AddNeededActionWithRequirements(al, FleetBeacon, ActionProduceFleetBeacon.Instance);
				AddNeededActionWithRequirements(al, Forge, ActionProduceForge.Instance);
				AddNeededActionWithRequirements(al, HighTemplar, ActionProduceHighTemplar.Instance);
				AddNeededActionWithRequirements(al, Immortal, ActionProduceImmortal.Instance);
				AddNeededActionWithRequirements(al, Mothership, ActionProduceMothership.Instance);
				AddNeededActionWithRequirements(al, Nexus, ActionProduceNexus.Instance);
				AddNeededActionWithRequirements(al, Observer, ActionProduceObserver.Instance);
				AddNeededActionWithRequirements(al, Phoenix, ActionProducePhoenix.Instance);
				AddNeededActionWithRequirements(al, PhotonCannon, ActionProducePhotonCannon.Instance);
				AddNeededActionWithRequirements(al, Pylon, ActionProducePylon.Instance);
				AddNeededActionWithRequirements(al, RoboticsBay, ActionProduceRoboticsBay.Instance);
				AddNeededActionWithRequirements(al, RoboticsFacility, ActionProduceRoboticsFacility.Instance);
				AddNeededActionWithRequirements(al, Sentry, ActionProduceSentry.Instance);
				AddNeededActionWithRequirements(al, Stalker, ActionProduceStalker.Instance);
				AddNeededActionWithRequirements(al, Stargate, ActionProduceStargate.Instance);
				AddNeededActionWithRequirements(al, TemplarArchives, ActionProduceTemplarArchives.Instance);
				AddNeededActionWithRequirements(al, TwilightCouncil, ActionProduceTwilightCouncil.Instance);
				AddNeededActionWithRequirements(al, VoidRay, ActionProduceVoidRay.Instance);
				AddNeededActionWithRequirements(al, WarpPrism, ActionProduceWarpPrism.Instance);
				AddNeededActionWithRequirements(al, Zealot, ActionProduceZealot.Instance);

				return al;
			}
		}
	}
}
